package com.kxmall.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.*;

@Slf4j
public class PageData extends LinkedHashMap implements Map {

	private static final long serialVersionUID = 1L;

	Map map = null;
	HttpServletRequest request;

	public PageData(HttpServletRequest request) {
		this.request = request;
		Map properties = request.getParameterMap();
		Map returnMap = new HashMap();
		Iterator entries = properties.entrySet().iterator();
		Entry entry;
		String name = "";
		String value = "";
		while (entries.hasNext()) {
			entry = (Entry) entries.next();
			name = (String) entry.getKey();
			Object valueObj = entry.getValue();
			if (null == valueObj) {
				value = "";
			} else if (valueObj instanceof String[]) {
				String[] values = (String[]) valueObj;
				for (int i = 0; i < values.length; i++) {
					value = values[i] + ",";
				}
				value = value.substring(0, value.length() - 1);
			} else {
				value = valueObj.toString();
			}
			returnMap.put(name, value);
		}
		map = returnMap;
	}

	public PageData() {
		map = new LinkedHashMap();
	}

	public PageData(Object obj) {
		Map returnMap = new HashMap();
		Class c;
		try {
			c = Class.forName(obj.getClass().getName());
			Method[] m = c.getMethods();
			for (int i = 0; i < m.length; i++) {
				String method = m[i].getName();
				if (method.startsWith("get")) {
					try {
						Object value = m[i].invoke(obj);
						if (value != null) {
							String key = method.substring(3);
							key = key.substring(0, 1).toLowerCase() + key.substring(1);
							returnMap.put(key, value);
						}
					} catch (Exception e) {
						log.error("error:" + method);
					}
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		map = returnMap;
	}

	/** 
     * @description 将xml字符串转换成map 
     * @param xml 
     * @return Map 
     */  
    public static PageData readStringXmlOut(String xml) {
    	PageData pd = new PageData();
		if(StringUtils.isNotEmpty(xml)){
			try {
				Document doc = parseText(xml); // 将字符串转为XML
				Element rootElt = doc.getRootElement(); // 获取根节点
				List<Element> list = rootElt.elements();//获取根节点下所有节点
				for (Element element : list) {  //遍历节点
					pd.put(element.getName(), element.getText()); //节点的name为map的key，text为map的value
				}
			} catch (DocumentException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
        return pd;  
    } 
    
    public String toXmlString(){
    	Document doc = DocumentHelper.createDocument();
    	
    	Element rootElt = doc.addElement("xml");
    	map.entrySet();
        for (Object obj : map.entrySet()) {
        	Entry<String, Object> entry = (Entry<String, Object>)obj;
        	Element element = rootElt.addElement(entry.getKey());
        	element.addCDATA((String) entry.getValue());
        }
        
        return doc.asXML();
    }
    
	@Override
	public Object get(Object key) {
		Object obj = null;
		if (map.get(key) instanceof Object[]) {
			Object[] arr = (Object[]) map.get(key);
			obj = arr;
		} else {
			obj = map.get(key);
		}
		return obj;
	}

	public String getString(Object key) {
		Object value = get(key);
		if(value==null)
			return null;
		else if(value instanceof String)
			return (String)value;
		else
			return value.toString();
	}

	public Integer getInt(Object key) {
    	try {
			return (Integer) get(key);
		}catch (Exception e){

		}
    	return null;
	}

	public Long getLong(Object key) {
		return (Long) get(key);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object put(Object key, Object value) {
		return map.put(key, value);
	}

	@Override
	public Object remove(Object key) {
		return map.remove(key);
	}

	public void clear() {
		map.clear();
	}

	public boolean containsKey(Object key) {
		return map.containsKey(key);
	}

	public boolean containsValue(Object value) {
		return map.containsValue(value);
	}

	public Set entrySet() {
		return map.entrySet();
	}

	public boolean isEmpty() {
		return map.isEmpty();
	}

	public Set keySet() {
		return map.keySet();
	}

	@SuppressWarnings("unchecked")
	public void putAll(Map t) {
		map.putAll(t);
	}

	public int size() {
		return map.size();
	}

	public Collection values() {
		return map.values();
	}

	@Override
	public String toString() {
		return "PageData{" +
				"map=" + map +
				'}';
	}

	public static Document parseText(String text) throws DocumentException {
		SAXReader reader = new SAXReader();
		try {
			reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
			reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
			reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
			reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
		} catch (SAXException e) {
			log.error(e.getMessage(),e);
		}

		String encoding = getEncoding(text);

		InputSource source = new InputSource(new StringReader(text));
		source.setEncoding(encoding);

		Document result = reader.read(source);

		// if the XML parser doesn't provide a way to retrieve the encoding,
		// specify it manually
		if (result.getXMLEncoding() == null) {
			result.setXMLEncoding(encoding);
		}

		return result;
	}

	private static String getEncoding(String text) {
		String result = null;

		String xml = text.trim();

		if (xml.startsWith("<?xml")) {
			int end = xml.indexOf("?>");
			String sub = xml.substring(0, end);
			StringTokenizer tokens = new StringTokenizer(sub, " =\"\'");

			while (tokens.hasMoreTokens()) {
				String token = tokens.nextToken();

				if ("encoding".equals(token)) {
					if (tokens.hasMoreTokens()) {
						result = tokens.nextToken();
					}

					break;
				}
			}
		}

		return result;
	}
}
